﻿
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;

namespace Red.Controls
{
    /// <summary>
    /// Canvas-based image with switchable base and alternate look
    /// </summary>
    public class RedIcon : ElementFacade<Rectangle>
    {
        #region Data

        private const string _defaultFillBrushName = "LabelTextBrush";
        private const string _defaultDisabledFillBrushName = "GrayBrush3";

        #endregion

        #region Properties

        public static readonly DependencyProperty CanvasProperty =
            DependencyProperty.Register(
                "Canvas", typeof( Canvas ), typeof( RedIcon ),
                new FrameworkPropertyMetadata( null, CanvasPropertyChanged )
                );

        public static readonly DependencyProperty AlternateCanvasProperty =
            DependencyProperty.Register(
                "AlternateCanvas", typeof( Canvas ), typeof( RedIcon ),
                new FrameworkPropertyMetadata( null, AlternateCanvasPropertyChanged )
                );

        public static readonly DependencyProperty UseAlternateCanvasProperty =
            DependencyProperty.Register(
                "UseAlternateCanvas", typeof( bool ), typeof( RedIcon ),
                new FrameworkPropertyMetadata( false, UseAlternateCanvasPropertyChanged )
                );

        public static readonly DependencyProperty FillProperty =
            DependencyProperty.Register(
                "Fill", typeof( Brush ), typeof( RedIcon ),
                new FrameworkPropertyMetadata( null, FillPropertyChanged )
                );

        public static readonly DependencyProperty DisabledFillProperty =
            DependencyProperty.Register(
                "DisabledFill", typeof( Brush ), typeof( RedIcon ),
                new FrameworkPropertyMetadata( null, DisabledFillPropertyChanged )
                );

        /// <summary>
        /// Base image
        /// </summary>
        public Canvas Canvas
        {
            get { return (Canvas)GetValue( CanvasProperty ); }
            set { SetValue( CanvasProperty, value ); }
        }

        /// <summary>
        /// Alternate image
        /// </summary>
        public Canvas AlternateCanvas
        {
            get { return (Canvas)GetValue( AlternateCanvasProperty ); }
            set { SetValue( AlternateCanvasProperty, value ); }
        }

        /// <summary>
        /// Whether to use base or alternate image
        /// </summary>
        public bool UseAlternateCanvas
        {
            get { return (bool)GetValue( UseAlternateCanvasProperty ); }
            set { SetValue( UseAlternateCanvasProperty, value ); }
        }

        /// <summary>
        /// Fill brush
        /// </summary>
        public Brush Fill
        {
            get { return (Brush)GetValue( FillProperty ); }
            set { SetValue( FillProperty, value ); }
        }

        /// <summary>
        /// Fill brush when control is disabled
        /// </summary>
        public Brush DisabledFill
        {
            get { return (Brush)GetValue( DisabledFillProperty ); }
            set { SetValue( DisabledFillProperty, value ); }
        }

        #endregion Properties

        #region C-tor
        
        public RedIcon()
        {
            Loaded += OnLoaded;
            IsEnabledChanged += OnIsEnabledChanged;
        }

        #endregion C-tor

        #region Event handlers

        private static void CanvasPropertyChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
        {
            var icon = d as RedIcon;
            if ( icon != null )
                icon.ApplyCanvas( e.NewValue as Canvas, (Canvas)d.GetValue( AlternateCanvasProperty ) );
        }
        
        private static void AlternateCanvasPropertyChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
        {
            var icon = d as RedIcon;
            if ( icon != null )
                icon.ApplyCanvas( (Canvas)d.GetValue( CanvasProperty ), e.NewValue as Canvas );
        }

        private static void UseAlternateCanvasPropertyChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
        {
            var icon = d as RedIcon;
            if ( icon != null )
                icon.ApplyCanvas( (Canvas)d.GetValue( CanvasProperty ), (Canvas)d.GetValue( AlternateCanvasProperty ) );
        }

        private static void FillPropertyChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
        {
            var icon = d as RedIcon;
            if ( icon != null && icon.IsEnabled )
                icon.Element.Fill = e.NewValue as Brush;
        }

        private static void DisabledFillPropertyChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
        {
            var icon = d as RedIcon;
            if ( icon != null && !icon.IsEnabled )
                icon.Element.Fill = e.NewValue as Brush;
        }

        void OnLoaded( object sender, RoutedEventArgs e )
        {
            if ( Fill == null )
            {
                SetResourceReference( FillProperty, _defaultFillBrushName );
            }

            if ( DisabledFill == null )
            {
                SetResourceReference( DisabledFillProperty, _defaultDisabledFillBrushName );
            }
        }

        private void OnIsEnabledChanged( object sender, DependencyPropertyChangedEventArgs e )
        {
            if ( true.Equals( e.NewValue ) )
            {
                Element.Fill = Fill;
            }
            else
            {
                Element.Fill = DisabledFill;
            }
        }

        #endregion Event handlers

        #region Implementation
        
        protected override Size MeasureOverride( Size availableSize )
        {
            var result = availableSize;
            if ( Double.IsPositiveInfinity( result.Width ) || Double.IsPositiveInfinity( result.Height ) )
            {
                Canvas canvas = UseAlternateCanvas ? AlternateCanvas : Canvas;
                if ( Double.IsPositiveInfinity( result.Width ) ) result.Width = canvas != null ? canvas.Width : 0;
                if ( Double.IsPositiveInfinity( result.Height ) ) result.Height = canvas != null ? canvas.Height : 0;
            }
            return result;
        }
        
        #endregion Implementation

        #region Private methods

        private void ApplyCanvas( Canvas normal, Canvas alternate )
        {
            Canvas canvas = UseAlternateCanvas && alternate != null ? alternate : normal;
            if ( canvas != null )
                Element.OpacityMask = new VisualBrush( canvas ) { Stretch = Stretch.Uniform };
            else
                Element.OpacityMask = null;
        }

        #endregion Private methods
    }
}